// useVoiceChat.ts
import { shallowRef, shallowReactive, onUnmounted } from "vue";
import type { ShallowRef } from "vue";
import AgoraRTC, {
  ClientRole,
  type IAgoraRTCClient,
  type ILocalAudioTrack,
  type UID,
} from "agora-rtc-sdk-ng";
import { ElMessage } from "element-plus";

/**
 * 语音聊天室配置接口
 * @property appId - 声网项目 App ID（必须）
 * @property token - 动态生成的频道鉴权 Token（必须）
 * @property channel - 频道名称（必须）
 * @property uid - 用户唯一标识（建议由服务端生成）
 * @property role - 初始用户角色，默认观众
 */
interface VoiceConfig {
  appId: string;
  token: string;
  channel: string;
  uid: UID;
  role: ClientRole;
}
/**
 * @property uid -远端用户uid
 * @property subscribed - 是否订阅
 */
interface RemoteUser {
  uid: UID;
  subscribed: boolean;
}
const useVoiceChat = () => {
  // ===================== 响应式状态管理 =====================
  /**
   * RTC 客户端实例（shallowRef 优化性能）
   * @description 用于管理频道连接和媒体流发布
   */
  const client = shallowRef<IAgoraRTCClient | null>(null);
  /**
   * 频道配置（浅层响应式）
   * @description 包含频道连接必需参数，初始化后不建议直接修改
   */
  const config = shallowReactive<VoiceConfig>({
    appId: "",
    token: "",
    channel: "",
    uid: 0,
    role: "audience", // 初始角色设为观众
  });

  /**
   * 本地音频轨道管理（浅层响应式）
   * @property mic - 麦克风输入轨道
   * @property system - 系统音频捕获轨道
   */
  const audioTracks = shallowReactive<{
    mic?: ILocalAudioTrack;
    system?: ILocalAudioTrack;
  }>({});

  /**
   * 应用状态管理（浅层响应式）
   * @property isInitialized - SDK 是否完成初始化
   * @property isJoined - 是否已加入频道
   * @property isSpeaking - 本地用户是否正在发言
   * @property networkQuality - 上行网络质量评分（0-6，0 最好）
   * @property activeSpeakers - 当前活跃用户 UID 列表
   */
  const state = shallowReactive({
    isInitialized: false,
    isJoined: false,
    isSpeaking: false,
    networkQuality: 0,
    // 远端用户管理
    activeSpeakers: [] as UID[], //活跃用户
    remoteUsers: [] as RemoteUser[], // 所有远端用户（无论订阅状态）
    manualUnsubscribed: new Set<UID>(), // 手动取消订阅的用户（黑名单）
  });
  /**
   * 音频设备管理（浅层响应式）
   * @property mics - 可用的麦克风设备列表
   * @property currentMic - 当前选中的麦克风设备 ID
   */
  const devices = shallowReactive<{
    mics: MediaDeviceInfo[];
    currentMic: string;
  }>({
    mics: [],
    currentMic: "",
  });

  // ===================== 生命周期管理 =====================
  /** 用于取消未完成的异步操作 */
  let abortController = new AbortController();

  /** 清理未完成的异步操作并重置控制器 */
  const cleanup = () => {
    abortController.abort();
    abortController = new AbortController();
  };

  // ===================== 核心功能实现 =====================

  /**
   * 初始化 Agora RTC SDK
   * @param initConfig - 频道配置参数
   * @throws 初始化失败时抛出错误
   */
  const initialize = async (initConfig: VoiceConfig) => {
    cleanup();
    Object.assign(config, initConfig);

    try {
      // 创建 RTC 客户端实例
      client.value = AgoraRTC.createClient({
        mode: "live", // 直播模式，适合语音聊天室场景
        codec: "vp8", // 推荐编解码格式，兼容性更好
      });

      setupEventListeners();
      await loadDevices();
      state.isInitialized = true;
      ElMessage.success("SDK 初始化成功");
    } catch (error) {
      handleError("SDK 初始化失败", error);
      throw error; // 抛出错误供上层处理
    }
  };

  /**
   * 加载可用的麦克风设备列表
   * @description 获取系统麦克风设备并设置默认设备
   */
  const loadDevices = async () => {
    try {
      // 获取所有麦克风设备（需要浏览器权限）
      devices.mics = await AgoraRTC.getMicrophones();

      // 设置默认设备（优先选择已授权的设备）
      const authorizedDevice = devices.mics.find((d) => d.label);
      devices.currentMic = authorizedDevice?.deviceId || devices.mics[0]?.deviceId || "";
    } catch (error) {
      handleError("设备加载失败", error);
    }
  };

  /**
   * 设置 RTC 事件监听器
   * @description 处理用户加入/离开、网络质量、音量变化等事件
   */
  const setupEventListeners = async () => {
    if (!client.value) return;
    // 启用音量指示器
    client.value.enableAudioVolumeIndicator(); //  默认每2秒触发

    // 远端用户发布流事件
    client.value.on("user-published", async (user, mediaType) => {
      if (mediaType !== "audio") return;
      // 添加用户到列表（无论是否订阅）
      if (!state.remoteUsers.some((u) => u.uid === user.uid)) {
        state.remoteUsers.push({
          uid: user.uid,
          subscribed: !state.manualUnsubscribed.has(user.uid),
        });
      }
      // 自动订阅逻辑（不在黑名单则订阅）
      if (!state.manualUnsubscribed.has(user.uid)) {
        try {
          await client.value?.subscribe(user, "audio");
          user.audioTrack?.play();
          updateUserSubscription(user.uid, true);
          ElMessage.success(`自动订阅用户 ${user.uid} 成功`);
        } catch (error) {
          handleError("自动订阅失败", error);
        }
      }
    });

    // 远端用户取消发布事件
    client.value.on("user-unpublished", (user) => {
      client.value?.unsubscribe(user);
      // 从所有列表中移除
      state.remoteUsers = state.remoteUsers.filter((u) => u.uid !== user.uid);
      state.manualUnsubscribed.delete(user.uid);
      ElMessage.info(`用户 ${user.uid} 已下麦`);
    });

    // 网络质量报告（每秒触发）
    client.value.on("network-quality", (quality) => {
      state.networkQuality = quality.uplinkNetworkQuality;
    });

    // 音量变化指示器（每2秒触发）
    client.value.on("volume-indicator", (result) => {
      // 过滤出音量大于60的用户
      const activeUsers = result.filter((item) => item.level > 40);
      state.activeSpeakers = activeUsers.map((item) => item.uid);
      state.isSpeaking = activeUsers.some((item) => item.uid === config.uid);
      if (activeUsers.length) {
        ElMessage.success(`频道内的用户${state.activeSpeakers}正在发言并且阈值大于40`);
      }
      // 仅在当前用户说话时显示消息
      if (state.isSpeaking) {
        ElMessage.success(`当前用户正在发言阈值大于40: ${state.isSpeaking}`);
      }
      // console.log(activeUsers);
    });
  };

  /**
   * 加入语音频道
   * @description 根据配置参数连接至指定频道
   * @throws 加入失败时抛出错误
   */
  const join = async () => {
    if (!client.value) throw new Error("客户端未初始化");

    try {
      // 严格遵循参数顺序：appId, channel, token, uid
      await client.value.join(config.appId, config.channel, config.token, config.uid);

      // 设置用户角色（需在加入频道后调用）
      await client.value.setClientRole(config.role);
      state.isJoined = true;
      ElMessage.success("加入频道成功");
    } catch (error) {
      handleError("加入失败", error);
      throw error;
    }
  };

  // ===================== 手动控制方法 =====================
  /**
   * 手动订阅用户
   * @param uid - 目标用户ID
   */
  const subscribeUser = async (uid: UID) => {
    if (!client.value) return;

    // 从黑名单移除
    state.manualUnsubscribed.delete(uid);

    const user = client.value.remoteUsers.find((u) => u.uid === uid);
    if (user) {
      try {
        await client.value.subscribe(user, "audio");
        user.audioTrack?.play();
        updateUserSubscription(uid, true);
        ElMessage.success(`手动订阅用户 ${uid} 成功`);
      } catch (error) {
        handleError("订阅失败", error);
      }
    }
  };

  /**
   * 手动取消订阅
   * @param uid - 目标用户ID
   */
  const unsubscribeUser = async (uid: UID) => {
    if (!client.value) return;

    // 加入黑名单
    state.manualUnsubscribed.add(uid);

    const user = client.value.remoteUsers.find((u) => u.uid === uid);
    if (user) {
      try {
        await client.value.unsubscribe(user, "audio");
        user.audioTrack?.stop();
        updateUserSubscription(uid, false);
        ElMessage.success(`取消订阅用户 ${uid} 成功`);
      } catch (error) {
        handleError("取消订阅失败", error);
      }
    }
  };

  /**
   * 开启麦克风并发布音频流
   * @description 需要浏览器麦克风权限
   */
  const startMic = async () => {
    if (!state.isJoined) throw new Error("尚未加入频道");
    if (audioTracks.mic || !client.value) return;

    try {
      // 创建麦克风轨道（使用当前选定设备）
      audioTracks.mic = await AgoraRTC.createMicrophoneAudioTrack({
        microphoneId: devices.currentMic,
        encoderConfig: "speech_standard", // 语音优化编码
      });

      // 发布到频道
      await client.value.publish(audioTracks.mic);
      ElMessage.success("麦克风已开启");
    } catch (error) {
      handleError("麦克风启动失败", error);
      throw error;
    }
  };

  /**
   * 开启系统音频捕获（屏幕声音/其他应用音频）
   * @description 需要用户手动授权
   */
  const startSystemAudio = async () => {
    if (!state.isJoined) throw new Error("尚未加入频道");
    if (audioTracks.system || !client.value) return;

    try {
      // 获取系统音频流（需要用户交互触发）
      const stream = await navigator.mediaDevices.getUserMedia({
        audio: true,
        video: false,
      });

      // 创建自定义音频轨道
      audioTracks.system = AgoraRTC.createCustomAudioTrack({
        mediaStreamTrack: stream.getAudioTracks()[0],
        encoderConfig: "speech_standard",
      });

      // 发布到频道
      await client.value.publish(audioTracks.system);
      ElMessage.success("系统音频已开启");
    } catch (error) {
      handleError("系统音频捕获失败", error);
      throw error;
    }
  };
  /**
   * 切换麦克风设备
   * @param deviceId - 目标设备 ID
   * @description 需要先关闭旧设备再开启新设备
   */
  const switchMic = async (deviceId: string) => {
    if (!audioTracks.mic) throw new Error("麦克风未启用");

    try {
      // 取消发布并关闭旧轨道
      await client.value?.unpublish(audioTracks.mic);
      audioTracks.mic.close();
      audioTracks.mic = undefined;

      // 使用新设备创建轨道
      audioTracks.mic = await AgoraRTC.createMicrophoneAudioTrack({
        microphoneId: deviceId,
        encoderConfig: "speech_standard",
      });

      // 重新发布
      await client.value?.publish(audioTracks.mic);
      devices.currentMic = deviceId;
      ElMessage.success("麦克风已切换");
    } catch (error) {
      handleError("设备切换失败", error);
      throw error;
    }
  };

  // ===================== 上下麦管理 =====================
  /**
   * 申请上麦（观众 -> 主播）
   * @description 需要信令系统通知主播审批
   */
  const requestToHost = async () => {
    if (config.role === "host" || !client.value) return;

    try {
      // 模拟信令发送（需实现具体逻辑）
      // sendSignalToHost({ type: "REQUEST_HOST", uid: config.uid });

      // 等待审批结果（示例使用 setTimeout 模拟）
      const granted = await new Promise<boolean>((resolve) => {
        setTimeout(() => resolve(true), 3000); // 实际应监听信令返回
      });

      if (granted) {
        await switchToHost();
        ElMessage.success("上麦成功");
      }
    } catch (error) {
      handleError("上麦申请失败", error);
    }
  };

  /**
   * 切换为主播角色
   * @description 需要重新设置客户端角色
   */
  const switchToHost = async () => {
    if (!client.value) return;

    try {
      await client.value.setClientRole("host");
      config.role = "host";
      ElMessage.info("您现在是主播");
    } catch (error) {
      handleError("角色切换失败", error);
      throw error;
    }
  };

  /**
   * 下麦操作（主播 -> 观众）
   * @description 停止所有音频发布并切换角色
   */
  const leaveStage = async () => {
    if (!client.value) return;
    try {
      // 停止所有音频流
      await unpublishTrack("mic");
      await unpublishTrack("system");

      // 切换回观众角色
      await client.value.setClientRole("audience");
      config.role = "audience";
      ElMessage.info("已下麦");
    } catch (error) {
      handleError("下麦失败", error);
      throw error;
    }
  };
  /**
   * 离开频道并清理所有资源
   * @description 安全断开与频道的连接，释放所有音频资源
   */
  const leave = async () => {
    if (!client.value || !state.isJoined) return;
    try {
      // 第一步：离开频道
      await client.value.leave();

      // 第二步：关闭所有本地音频轨道
      audioTracks.mic?.close();
      audioTracks.system?.close();

      // 第三步：重置状态
      resetState();

      // 第四步：显示反馈
      ElMessage.success("已成功离开频道");
    } catch (error) {
      // 错误处理
      handleError("离开频道失败", error);
      throw error; // 抛出错误供上层处理
    }
  };

  // ===================== 辅助方法 =====================
  /**
   * 重置所有状态至初始值
   */
  const resetState = () => {
    state.isJoined = false;
    state.isSpeaking = false;
    state.activeSpeakers = [];
    state.networkQuality = 0;
    audioTracks.mic = undefined;
    audioTracks.system = undefined;
  };

  /**
   * 统一错误处理
   * @param msg - 错误前缀信息
   * @param error - 原始错误对象
   */
  const handleError = (msg: string, error: unknown) => {
    const err = error as Error;
    ElMessage.error(`${msg}: ${err.message || "未知错误"}`);
    console.error(`[Error] ${msg}:`, error);
  };

  /**
   * 更新用户订阅状态
   * @param uid - 用户ID
   * @param status - 新的订阅状态
   */
  const updateUserSubscription = (uid: UID, status: boolean) => {
    const index = state.remoteUsers.findIndex((u) => u.uid === uid);
    if (index !== -1) {
      state.remoteUsers[index].subscribed = status;
    }
  };

  // ===================== 生命周期管理 =====================
  // 组件卸载时自动清理资源
  onUnmounted(() => {
    leave();
    cleanup();
  });

  return {
    // 状态暴露
    client: client as ShallowRef<IAgoraRTCClient | null>,
    config,
    state,
    devices,
    audioTracks,

    // 方法暴露
    initialize,
    join,
    leave,
    startMic,
    stopMic: () => unpublishTrack("mic"),
    startSystemAudio,
    stopSystemAudio: () => unpublishTrack("system"),
    switchMic,
    requestToHost,
    leaveStage,
    subscribeUser,
    unsubscribeUser,
  };

  /**
   * 内部方法：取消发布指定类型轨道
   * @param type - 轨道类型（mic/system）
   */
  async function unpublishTrack(type: "mic" | "system") {
    const track = audioTracks[type];
    if (!track || !client.value) return;

    try {
      await client.value.unpublish(track);
      track.close();
      audioTracks[type] = undefined;
      ElMessage.success(`${type === "mic" ? "麦克风" : "系统音频"}已关闭`);
    } catch (error) {
      handleError("取消发布失败", error);
    }
  }
};

export default useVoiceChat;
